﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace Utils.Configuration
{
    public class JsonConfig
    {
        private JObject jObject = null;
        string _path;
        public string this[string key]
        {
            get
            {
                string str = "";
                if (jObject != null)
                {
                    str = GetValue(key);
                }
                return str;
            }
        }
        public JsonConfig(string path=default)
        {
            jObject = new JObject();
            if (string.IsNullOrWhiteSpace(path))
            {
                path = AppDomain.CurrentDomain.BaseDirectory + "config.json";
            }
            _path = path;
            using (StreamReader file = File.OpenText(path))
            {
                using (JsonTextReader reader = new JsonTextReader(file))
                {
                    jObject = JObject.Load(reader);
                }
            }
        }

        public T GetValue<T>(string key) where T : class
        {
            return JsonConvert.DeserializeObject<T>(jObject.SelectToken(key).ToString());
        }
        public string GetValue(string key)
        {
            return Regex.Replace((jObject.SelectToken(key).ToString()), @"\s", "");
        }

        public IList<T> GetValues<T>(string key) where T:class
        {
            JArray a = (JArray)jObject[key];
            IList<T> person = a.ToObject<IList<T>>();
            return person;
        }

        public Dictionary<string, string[]> GetKeyList(string key)
        {
            string json = GetValue(key);
            JObject o = JObject.Parse(json);

            Dictionary<string, string[]> keyList = new Dictionary<string, string[]>();
            foreach (JProperty jToken in o.Properties())
            {
                string[] jArray = ((JArray)jToken.Value).ToObject<List<string>>().ToArray();
                keyList.Add(jToken.Name.ToString(), jArray);
            }
            return keyList;
        }

        public Dictionary<string, string> GetKeyValue(string json)
        {
            JObject o = JObject.Parse(json);

            Dictionary<string, string> keyList = new Dictionary<string, string>();
            foreach (JProperty jToken in o.Properties())
            {
                keyList.Add(jToken.Name.ToString(), jToken.Value.ToString());
            }
            return keyList;
        }

        /// <summary>
        /// 写入某个节点
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        public void WriteToJsonFile(string key, string s)
        {
            jObject[key] = s;
            WriteToFile();
        }

        private void WriteToFile()
        {
            using (StreamWriter writer = new StreamWriter(_path))
            {
                using (JsonTextWriter jsonWriter = new JsonTextWriter(writer))
                {
                    jObject.WriteTo(jsonWriter);
                }
            }
        }

        /// <summary>
        /// 写入某个节点
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        public void WriteToJsonFile<T>(string key,T t)
        {
            string json = JsonConvert.SerializeObject(t);
            jObject[key] = JObject.Parse(json);
            WriteToFile();
        }
        /// <summary>
        /// 删除或修改 单个节点
        /// </summary>
        /// <param name="section">节点途径 格式为A.B.C  如果节点带数组格式  A.[0].C 数组用中括号</param>
        /// <param name="isRemove">是删除还是修改</param>
        /// <param name="value">修改节点的内容</param>
        /// <param name="isNum">修改内容类型 数据:true  字符串：false</param>
        public void JTokenHander(string section, bool isRemove, string value, bool isNum=false)
        {
            string[] nodes = section.Split('.');
            JToken tempToken=jObject as JToken;
            if (nodes.Length>0)
            {
                foreach (string node in nodes)
                {
                    if (node.StartsWith("[") && node.EndsWith("]"))
                    {
                        int tempi = 0;
                        if (int.TryParse(node.Trim('[').Trim(']'), out tempi))
                        {
                            tempToken = tempToken[tempi];
                        }
                    }
                    else
                    {
                        tempToken = tempToken[node];
                    }
                }
                if (tempToken != null)
                {
                    if (isRemove)
                    {
                        tempToken.Parent.Remove();
                    }
                    else
                    {
                        JToken token;
                        if (isNum)
                        {
                            if (value.Contains("."))
                            {
                                double.TryParse(value, out double tempd);
                                token = tempd;
                            }
                            else
                            {
                                int.TryParse(value, out int tempi);
                                token = tempi;
                            }

                        }
                        else
                        {
                            token = value;
                        }
                        tempToken.Replace(token);//改
                    }
                }
                WriteToFile();
            }
        }

        /// <summary>
        /// 删除指定节点
        /// </summary>
        /// <param name="section">节点途径 格式为A:B:C  如果节点带数组格式  A:[0]:C 数组用中括号</param>
        public void Remove(string section)
        {
            JTokenHander(section, true, "");
        }
        /// <summary>
        /// 修改指定节点内容
        /// </summary>
        /// <param name="section">节点途径 格式为A:B:C  如果节点带数组格式  A:[0]:C 数组用中括号</param>
        /// <param name="value">修改节点的内容</param>
        /// <param name="isNum">修改内容类型 数据:true  字符串：false</param>
        public void Update(string section, string value, bool isNum)
        {
            JTokenHander(section, false, value, isNum);
        }
    }
}
